home *** CD-ROM | disk | FTP | other *** search
- ;;; -*- Mode:Lisp; Package:Weyli; Base:10; Lowercase:T; Syntax:Common-Lisp -*-
- ;;; ===========================================================================
- ;;; Expanded Polynomials
- ;;; ===========================================================================
- ;;; (c) Copyright 1989, 1991 Cornell University
-
- ;;; $Id: grobner.lisp,v 2.6 1991/11/13 16:15:11 rz Exp $
-
- (in-package "WEYLI")
-
- (defmacro with-grobner-operations (grobner-basis &body body)
- `(with-slots (compare-function ring generators undones reducibles possibles)
- ,grobner-basis
- (macrolet ((e> (a b) `(%funcall compare-function ,a ,b))
- (e< (a b) `(%funcall compare-function ,b ,a)))
- ,@body)))
-
- ;; Grobner calculations are done within the context of an instance of
- ;; the Grobner-Basis flavor. Each instance has its own variable list
- ;; and flags sets. At any time the user can add polynomials or
- ;; extract information from the structure.
-
- (defclass grobner-basis ()
- ((ring :initarg :ring)
-
- ;; The exponent comparison function
- (compare-function :initform #'lexical->
- :initarg :compare-function
- :reader compare-function)
-
- ;; the current list of generators
- (generators :initform ())
-
- (undones :initform ())
- ;; A list of triples pairs (lt f g), lt(f)<=lt(g), of elements of
- ;; GENERATORS such that if any pair is not in the list, its s-poly
- ;; is guaranteed to be writable as a linear combination of
- ;; GENERATORS, with smaller s-degs
-
- (reducibles :initform nil)
- (possibles :initform nil)
- ))
-
- (defmethod print-object ((grob-struct grobner-basis) stream)
- (let ((gens (relations grob-struct)))
- (format stream "(~S~{, ~S~})"
- (first gens) (rest gens))))
-
- (defun check-same-domain (exprs)
- (let ((domain (domain-of (first exprs))))
- (loop for exp in (rest exprs)
- do (unless (eql domain (domain-of exp))
- (return nil))
- finally (return domain))))
-
- (defun make-ideal (&rest polys)
- (let ((domain (check-same-domain polys))
- ideal)
- (when (null domain)
- (error "Not all polynomials are from the same domain:~%~S"
- polys))
- (unless (typep domain 'polynomial-ring)
- (error "~S is not a polynomial ring"))
- (cond ((typep (coefficient-domain domain) 'field)
- (setq ideal (make-instance 'grobner-basis :ring domain)))
- (t (error "Can't deal with polynomials not over fields: ~S"
- domain)))
- (loop for p in polys
- do (add-relation ideal p))
- ideal))
-
- (defmethod (setf compare-function) (new-function (grob grobner-basis))
- (with-slots (ring compare-function generators reducibles possibles) grob
- (unless (eql compare-function new-function)
- (flet ((convert-list (list)
- (loop for poly in list
- collect
- (sort poly
- #'(lambda (a b)
- (%funcall new-function
- (first a) (first b)))))))
- (setq generators (convert-list generators))
- (setq reducibles (convert-list reducibles))
- (setq possibles (convert-list possibles))
- (setq compare-function new-function)))
- grob))
-
- (defmethod add-relation ((grob-struct grobner-basis) (relation mpolynomial))
- (with-slots (ring compare-function generators reducibles) grob-struct
- (let ((poly (make-epolynomial ring compare-function relation)))
- (push (poly-form poly) reducibles)
- poly)))
-
- (defmethod relations ((grob-struct grobner-basis))
- (with-slots (generators reducibles compare-function ring) grob-struct
- (append
- (loop for g in generators
- collect (make-instance 'epolynomial
- :domain ring
- :compare-function compare-function
- :form g))
- (loop for g in reducibles
- collect (make-instance 'epolynomial
- :domain ring
- :compare-function compare-function
- :form g)))))
-
- (defmethod reset-grobner-basis ((grob-struct grobner-basis))
- (with-slots (generators undones possibles reducibles) grob-struct
- (setq generators nil undones nil
- possibles nil reducibles nil)))
-
- #+Ignore
- (defun terms-s-poly (compare-function terms1 terms2)
- (let ((m (max (le terms1) (le terms2))))
- (gterms-difference compare-function
- (gterms-mon-times terms1 (- m (le terms1)) (lc terms2))
- (gterms-mon-times terms2 (- m (le terms2)) (lc terms1)))))
-
- ;; The following saves a bunch of consing, but not as much as I would expect
- (defun terms-s-poly (compare-function terms1 terms2)
- (let ((m (max (le terms1) (le terms2)))
- (ans-terms (list nil))
- (terms nil)
- sum x y xe ye xc yc new-xe new-ye)
- (macrolet
- ((collect-term (.e. .c.)
- `(progn (setf (rest terms) (make-terms , .e. , .c.))
- (setf terms (rest terms)))))
- (setq terms ans-terms)
- (setq x (red terms1) y (red terms2))
- (setq xe (- m (le terms1))
- xc (lc terms2)
- ye (- m (le terms2))
- yc (- (lc terms1)))
- (loop
- (cond ((terms0? x)
- (cond ((terms0? y) (return (rest ans-terms)))
- (t (collect-term (+ ye (le y)) (* yc (lc y)))
- (setq y (red y)))))
- ((or (terms0? y)
- (%funcall compare-function
- (setq new-xe (+ xe (le x)))
- (setq new-ye (+ ye (le y)))))
- (collect-term (+ xe (le x)) (* xc (lc x)))
- (setq x (red x)))
- ((%funcall compare-function new-ye new-xe)
- (collect-term new-ye (* yc (lc y)))
- (setq y (red y)))
- (t (setq sum (+ (* xc (lc x)) (* yc (lc y))))
- (unless (0? sum)
- (collect-term new-xe sum))
- (setq x (red x) y (red y))))))))
-
- (defmethod reduce-basis ((grob-struct grobner-basis))
- (with-grobner-operations grob-struct
- (flet ((criterion1 (degree f1 f2)
- (loop for p in generators do
- (when (and (not (eql p f1))
- (not (eql p f2))
- (dominates degree (le p)))
- (unless (member nil undones
- :test (lambda (x prod)
- (declare (ignore x))
- (let ((b1 (second prod))
- (b2 (third prod)))
- (or (and (eql f1 b1) (eql p b2))
- (and (eql f1 b2) (eql p b1))
- (and (eql p b1) (eql f2 b2))
- (and (eql p b2) (eql f2 b1))))))
- (return-from criterion1 t))))))
- (let (temp f1 f2 h)
- (reduce-all grob-struct)
- (new-basis grob-struct)
- (loop while undones do
- (setq temp (pop undones))
- (setq f1 (second temp) f2 (third temp))
- (when (and (null (criterion1 (first temp) f1 f2))
- (not (disjoint (le f1) (le f2))))
- (setq h (terms-reduce compare-function
- (gterms-prim*
- (terms-s-poly compare-function f1 f2))
- generators))
- (when (not (terms0? h))
- (setq reducibles nil)
- (setq possibles (list h))
- (setq generators
- (loop for g in generators
- when (dominates (le g) (le h))
- do (push g reducibles)
- else collect g))
- (setq undones
- (loop for undone in undones
- unless (or (member (second undone) reducibles)
- (member (third undone) reducibles))
- collect undone))
- (reduce-all grob-struct)
- (new-basis grob-struct)))))))
- grob-struct)
-
- ;; This makes sure that all of the polynomials in gneerators and
- ;; possibles are AUTOREDUCED.
- (defmethod reduce-all ((grob-struct grobner-basis))
- (with-grobner-operations grob-struct
- (let (h g0)
- (loop while (not (null reducibles)) do
- (setq h (terms-reduce compare-function
- (pop reducibles)
- (append generators possibles)))
- (unless (terms0? h)
- (setq generators (loop for elt in generators
- when (dominates (le elt) (le h))
- do (push elt reducibles)
- (push elt g0)
- else collect elt))
- (setq possibles (loop for elt in possibles
- when (dominates (le elt) (le h))
- do (push elt reducibles)
- else collect elt))
- (setq undones (loop for (nil f1 f2) in undones
- when (and (not (member f1 g0))
- (not (member f2 g0)))
- collect (list (max (le f1) (le f2)) f1 f2)))
- (push h possibles))))))
-
- (defmethod new-basis ((grob-struct grobner-basis))
- (with-grobner-operations grob-struct
- (flet ((add-undone (f g)
- (when (e> (le f) (le g))
- (rotatef f g))
- (loop for (nil ff gg) in undones
- do (when (and (eql ff f) (eq gg g))
- (return t))
- finally (push (list (max (le f) (le g)) f g) undones))))
- (setq generators (append generators possibles))
- (loop for g in generators do
- (loop for elt in possibles do
- (when (not (eql elt g))
- (add-undone elt g))))
- (setq possibles nil)
- (setq undones (sort undones (lambda (a b) (e< (first a) (first b)))))
- #+ignore
- (setq generators
- (loop for g in generators
- for h = (terms-reduce compare-function g (remove g generators))
- when (not (terms0? h))
- collect h)))))
-
- ;; Reduce terms modulo the current basis
- (defun terms-reduce (compare-function terms basis)
- #+ignore
- (format t "~&~%Poly = ~S~%Basis: "
- (le terms))
- #+ignore
- (princ (mapcar (lambda (f) (le f)) basis))
- (let ((again t))
- (loop while again do
- (when (terms0? terms)
- (return nil))
- #+ignore
- (format t "~&Terms = ~S"
- (make-instance 'epolynomial
- :domain (slot-value grob-struct 'ring)
- :compare-function compare-function
- :form terms))
- (loop for g in basis
- do (when (dominates (le terms) (le g))
- (setq terms (gterms-prim*
- (terms-s-poly compare-function terms g)))
- (return t))
- finally (setq again nil))))
- #+ignore
- (format t "~&Result = ~S~%" (le terms))
- terms)
-
- ;; Make poly primitive.
- ;; This isn't really well defined since coefs are in a field. Idea is
- ;; to make the coefficients smaller. Its really worth avoiding
- ;; dividing out a content of 1!!!
- #+ignore ;; Use for integral domains
- (defun gterms-prim* (poly)
- (unless (terms0? poly)
- (let ((coef-domain (domain-of (lc poly)))
- (num-gcd (numerator (lc poly)))
- (den-gcd (denominator (lc poly)))
- 1/content)
- ;; Should really use a probabilistic algorithm content algorithm
- ;; here
- (map-over-each-term (red poly) (nil c)
- (if (1? num-gcd)
- (if (1? den-gcd) (return t)
- (setq den-gcd (gcd den-gcd (denominator c))))
- (if (1? den-gcd)
- (setq num-gcd (gcd num-gcd (numerator c)))
- (setq num-gcd (gcd num-gcd (numerator c))
- den-gcd (gcd den-gcd (denominator c))))))
- (unless (and (1? num-gcd) (1? den-gcd))
- (setq 1/content (make-quotient-element coef-domain den-gcd num-gcd))
- (map-over-each-term poly (e c)
- (update-term e (* c 1/content))))))
- poly)
-
- ;; Use for fields
- (defun gterms-prim* (poly)
- (unless (terms0? poly)
- (let ((1/lc (/ (lc poly))))
- (unless (1? 1/lc)
- (map-over-each-term poly (e c)
- (update-term e (* c 1/lc))))))
- poly)
-